﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClusteringProblem.Maths.QualityMeasures
{
    public class ClassificationError : QualityMeasureStrategy
    {
        public override double Compute(List<Model.IAntType> result, List<Model.Object> source)
        {
            double sum = 0.0;

            AdjustGroups(result, source);

            var groupIDs = source.Select(x => x.GroupID).Distinct().ToList();

            var joined2 = (from c in result
                          join d in source on c.ObjectID equals d.ID.ToString()
                          select new { c.ResultGroupID, d.GroupID }).ToList();

            groupIDs.ForEach(x =>
            {
                var theGroup = joined2.Where(y => y.GroupID == x);
                int different = theGroup.Where(z => z.ResultGroupID != z.GroupID).Count();

                sum += (double)different / theGroup.Count();
            });

            return sum / result.Count;
        }

        private static void AdjustGroups(List<Model.IAntType> result, List<Model.Object> source)
        {
            try
            {
                List<Tuple<string, string, int>> counters = new List<Tuple<string, string, int>>();
                Dictionary<string, string> mapping = new Dictionary<string, string>();

                var originalGroupIDs = source.Select(x => x.GroupID).Distinct();
                var resultGroupIDs = result.Select(x => x.ResultGroupID).Distinct();
                var joined = from c in result
                             join d in source on c.ObjectID equals d.ID.ToString()
                             select new { ID = d.ID, ResultGroup = c.ResultGroupID, SourceGroup = d.GroupID };

                foreach (var original in originalGroupIDs)
                    foreach (var group in resultGroupIDs)
                    {
                        int count = joined.Where(x => x.SourceGroup == original)
                                          .Where(x => x.ResultGroup == group)
                                          .Count();

                        counters.Add(new Tuple<string, string, int>(original, group, count));
                    }

                foreach (var original in originalGroupIDs)
                {
                    var key = counters.Where(x => x.Item1 == original)
                                      .OrderByDescending(x => x.Item3)
                                      .Select(x => x.Item2)
                                      .First();

                    mapping.Add(key, original);
                    counters.RemoveAll(x => x.Item2 == key);
                }

                result.ForEach(x =>
                {
                    x.ResultGroupID = mapping[x.ResultGroupID];
                });
            }
            catch(Exception)
            {
                return;
            }
        }
    }
}
